<div class="form-group pull-right">
  <pfng-toast-notification-list [notifications]="notifications"
      (onCloseSelect)="handleCloseNotification($event)" [showClose]="true">
  </pfng-toast-notification-list>
</div>

<div *ngIf="serviceView | async as view">
  <div class="container-fluid breadcrumb-bar">
    <div class="row">
      <ol class="breadcrumb">
        <li><a [routerLink]="['/services']">Services &amp; APIs</a></li>
        <li><a [routerLink]="['/services', view.service.id]">{{ view.service.name }} - {{ view.service.version }}</a></li>
        <li>Operation {{ operationName }}</li>
      </ol>
    </div>
  </div>

  <div class="row">
    <div class="col-md-8">
      <h1>{{ view.service.name }} - {{ view.service.version }} - {{ operationName }}</h1>
      <small>Review and adapt parameters constraints and dispatcher properties for mocks on operation {{ operationName }}. Be sure to know what you're doing: it may break your mocks!</small>

      <h3 class="section-label" *ngIf="view.service.type === 'REST'">Parameters Constraints</h3>

      <div class="parameters-constraints" *ngIf="view.service.type === 'REST'">
        <h5 class="subsection">Query parameters</h5>
        <div class="constraint-editor-entry constraint-editor-entry-header"
                *ngIf="paramConstraints['query'] != null && paramConstraints['query'].length > 0">
          <div class="constraint-editor-header name-header">Name</div>
          <div class="constraint-editor-header required-header text-center">Required?</div>
          <div class="constraint-editor-header recopy-header text-center">Recopy?</div>
          <div class="constraint-editor-header regexp-header text-center">Match Regexp?</div>
        </div>
        <div class="constraint-editor" *ngFor="let constraint of paramConstraints['query'], let i = index">
          <div class="constraint-editor-entry">
            <div class="constraint-editor-input">
              <input class="form-control" type="text" placeHolder="Name" name="name" [(ngModel)]="constraint.name"/>
            </div>
            <div class="constraint-editor-input text-center">
              <input type="checkbox" name="required" [(ngModel)]="constraint.required" style="vertical-align: middle;"/>
            </div>
            <div class="constraint-editor-input text-center">
              <input type="checkbox" name="recopy" [(ngModel)]="constraint.recopy"/>
            </div>
            <div class="constraint-editor-input">
                <input class="form-control" type="text" placeHolder="" name="mustMatchRegexp" [(ngModel)]="constraint.mustMatchRegexp">
            </div>
            <div class="constraint-editor-buttons">
              <a (click)="removeParameterConstraint('query', i)" class="as-item-delete" role="button">
                <i class="pficon pficon-close"></i>
              </a>
            </div>
          </div>
        </div>
        <a (click)="addParameterConstraint('query')" role="button">Add Parameter Constraint</a>

        <h5 class="subsection">Header parameters</h5>
        <div class="constraint-editor-entry constraint-editor-entry-header"
                *ngIf="paramConstraints['header'] != null && paramConstraints['header'].length > 0">
          <div class="constraint-editor-header name-header">Name</div>
          <div class="constraint-editor-header required-header text-center">Required?</div>
          <div class="constraint-editor-header recopy-header text-center">Recopy?</div>
          <div class="constraint-editor-header regexp-header text-center">Match Regexep?</div>
        </div>
        <div class="constraint-editor" *ngFor="let constraint of paramConstraints['header'], let i = index">
          <div class="constraint-editor-entry">
            <div class="constraint-editor-input">
              <input class="form-control" type="text" placeHolder="Name" name="name" [(ngModel)]="constraint.name"/>
            </div>
            <div class="constraint-editor-input text-center">
              <input type="checkbox" name="required" [(ngModel)]="constraint.required" style="vertical-align: middle;"/>
            </div>
            <div class="constraint-editor-input text-center">
              <input type="checkbox" name="recopy" [(ngModel)]="constraint.recopy"/>
            </div>
            <div class="constraint-editor-input">
                <input class="form-control" type="text" placeHolder="" name="mustMatchRegexp" [(ngModel)]="constraint.mustMatchRegexp">
            </div>
            <div class="constraint-editor-buttons">
              <a (click)="removeParameterConstraint('header', i)" class="as-item-delete" role="button">
                <i class="pficon pficon-close"></i>
              </a>
            </div>
          </div>
        </div>
        <a (click)="addParameterConstraint('header')" role="button">Add Header Constraint</a>
      </div>
      <div class="pull-right" *ngIf="view.service.type === 'REST'">
        <button type="button" class="btn btn-default" (click)="resetOperationProperties()">Reset</button>&nbsp;
        <button type="submit" class="btn btn-primary" (click)="saveOperationProperties()" ng-disabled="form.$invalid">Save</button>
      </div>
      <br/><br/>

      <h3 class="section-label">Current dispatching properties</h3>
      <div class="row">
        <div class="col-md-6">
          <dl class="dl-horizontal left">
          <span *ngIf="view.service.type === 'SOAP_HTTP'">
            <dt>SOAP Action:</dt>
            <dd><code>{{ operation!.action }}</code></dd>
          </span>
          <dt>Dispatcher:</dt>
          <dd><code>{{ operation!.dispatcher }}</code> &nbsp;
            <span class="learn-more-inline">
              <a href="https://microcks.github.io">Learn More
                <i class="fa fa-external-link" aria-hidden="true"></i>
              </a>
            </span>
          </dd>
          <dt>Dispatching rules:</dt>
          <dd><code class="code-block">{{ operation!.dispatcherRules }}</code></dd>
          </dl>
        </div>
        <div class="col-md-6">
          <dl class="dl-horizontal left">
            <span *ngIf="view.service.type === 'SOAP_HTTP'">
              <dt>Message Output Name:</dt>
              <dd><code>{{ operation!.outputName }}</code></dd>
            </span>
            <dt *ngIf="!isEventTypeService()">HTTP Verb:</dt>
            <dt *ngIf="isEventTypeService()">Type:</dt>
            <dd>
              <div [ngSwitch]="operation!.method">
                <span class="label label-success" *ngSwitchCase="'GET'">GET</span>
                <span class="label label-primary" *ngSwitchCase="'PUT'">PUT</span>
                <span class="label label-danger" *ngSwitchCase="'DELETE'">DELETE</span>
                <span class="label label-warning" *ngSwitchCase="'POST'">POST</span>
                <span class="label label-info" *ngSwitchDefault>{{ operation!.method }}</span>
              </div>
            </dd>
            <span *ngIf="!isEventTypeService()">
              <dt>Default delay:</dt>
              <dd>{{ operation?.defaultDelay || 0 }} ms with <code>{{ operation?.defaultDelayStrategy || 'fixed' }}</code> strategy</dd>
            </span>
            <span *ngIf="isEventTypeService()">
              <dt>Frequency:</dt>
              <dd>{{ operation?.defaultDelay || 0 }} sec</dd>
            </span>
          </dl>
        </div>
      </div>

      <h3 class="section-label">New dispatching properties</h3>
      <div class="row">
        <div class="col-md-7">
          <span *ngIf="!isEventTypeService()">
            <div class="control-group form-inline">
              <label class="control-label" for="defaultDelay">Default delay</label>
              <div class="controls">
                <input class="form-control" id="defaultDelay" name="defaultDelay" [(ngModel)]="newOperation!.defaultDelay"/> ms
                <p class="help-block">The delay to wait before returning response.</p>
              </div>
            </div>
            <div class="control-group form-inline">
              <label class="control-label" for="defaultDelay">Default delay strategy</label>
              <div class="controls">
                <input class="form-control" id="defaultDelayStrategy" name="defaultDelayStrategy" [(ngModel)]="newOperation!.defaultDelayStrategy"/>
                <p class="help-block">The strategy to apply to default delay (can be <code>fixed</code>, <code>random</code> or <code>random-(\d)</code> to specify a range).</p>
              </div>
            </div>
          </span>
          <span *ngIf="isEventTypeService()">
            <div class="control-group form-inline">
              <label class="control-label" for="defaultDelay">Frequency</label>
              <div class="controls">
                <select class="form-control" name="defaultDelay" [(ngModel)]="newOperation!.defaultDelay" [disabled]="!isAsyncMockEnabled()">
                  <option *ngFor="let frequency of frequencies" [value]="frequency">{{ frequency }} </option>
                </select> &nbsp; sec
                <div class="pull-right">
                  <button class="btn btn-warning" *ngIf="isAsyncMockEnabled()" (click)="disableAsyncMock()">Disable</button>
                  <button class="btn btn-success" *ngIf="!isAsyncMockEnabled()" (click)="enableAsyncMock()">Enable</button>
                </div>
                <p class="help-block">The frequency of messages publication.</p>
              </div>
            </div>
          </span>
          <div class="control-group">
            <label class="control-label" for="dispatcher">Dispatcher</label>
            <div class="controls">
              <select class="form-control" id="dispatcher" name="dispatcher" [(ngModel)]="newOperation!.dispatcher">
                <option *ngFor="let dispatcher of dispatchersByServiceType[view.service.type]" [value]="dispatcher.value">{{ dispatcher.value }} </option>
              </select>
              <p class="help-block">The dispatcher used by Operation.</p>
            </div>
          </div>
          <div class="control-group">
            <label class="control-label" for="dispatcherRules">Dispatcher rules</label>
            <div class="controls">
              <textarea class="form-control" rows="10" id="dispatcherRules" name="dispatcherRules" [(ngModel)]="newOperation!.dispatcherRules">
              </textarea>
              <p class="help-block">The dispatcher rules for above dispatcher.</p>
            </div>
          </div>
        </div>
        <div class="col-md-4">
          <h4 class="section-label text-right" *ngIf="!isEventTypeService()">Available responses</h4>
          <h4 class="section-label text-right" *ngIf="isEventTypeService()">Available messages</h4>

          <div class="text-right" *ngFor="let exchange of view.messagesMap[operationName]">
            <span *ngIf="!isEventTypeService()">
              <h2>
                <span class="label label-primary">
                  <span class="fa fa-play" *ngIf="isRequestTriable()" (click)="tryRequest(getReqRespPair(exchange))"
                        tooltip="Try it now!" placement="top">&nbsp;</span>
                  {{ getReqRespPair(exchange).response.name }} - {{ getReqRespPair(exchange).response.dispatchCriteria }}
                </span>
              </h2>
            </span>
            <span *ngIf="isEventTypeService()">
              <h2><span class="label label-primary">{{ getUnidirEvent(exchange).eventMessage.name }} </span></h2>
            </span>
          </div>
        </div>
      </div>

      <div class="pull-right">
        <button type="button" class="btn btn-default" (click)="resetOperationProperties()">Reset</button>&nbsp;
        <button type="submit" class="btn btn-primary" (click)="saveOperationProperties()" ng-disabled="form.$invalid">Save</button>
      </div>

      <br/><br/>
      <div *ngIf="!isEventTypeService()">
        <h3 class="section-label"><i class="fa fa-bug toggle-button-icon"></i> Live Traces</h3>
        <app-live-traces
          [initialServiceName]="view.service.name"
          [initialOperationName]="operationName">
        </app-live-traces>
      </div>
      <br/><br/>
    </div>

    <div class="col-md-4 help-bar">
      <h3 class="section-label">Help needed?</h3>
      <small>This sidebar provides some explanations and examples on how to setup parameter constraints and use the evolved dispatchers.</small>
      <br/>
      <h4>Parameters Constraints</h4>
      <p>
        Parameters constraints allows you to define expectations regarding incoming header or query parameters values.
        Adding constraints add new behaviour on your operation mocks so that they can:
      </p>
      <ul>
        <li>check presence of parameter using the <code>required</code> flag,</li>
        <li><code>recopy</code> incoming parameter value into an outgoing header (think of transaction propagation for example),</li>
        <li><code>match</code> parameter value using a `regular expression` (think of Authorization token validation for example)</li>
      </ul>

      <div id="fallback-help" *ngIf="newOperation?.dispatcher === 'FALLBACK'">
        <br/>
        <h4>Fallback Dispatcher</h4>
        <p>
          Fallback dispatcher allows you to declare a <code>fallback</code> response in case the incoming request to your mocks do not
          match any existing dispatch criteria.
        </p>
        <p>
          Consider the following case where you have a single <code>GET /user/:name</code> operation. You've defined mocks responses called
          <code>Andrew</code>, <code>Anna</code> and <code>John Doe</code> that are matching with corresponding <code>:name</code> resource path.
          What if name does not have one of these values?
        </p>
        <p>
          By default Microcks will return a <code>404</code> error. But if you've defined a <code>FALLBACK</code> dispatcher, you'll default to
          the response of your choice. Just say you want to default to <code>John Doe</code> response:
        </p>
        <div style="position: absolute; right: 20px">
          <button class="btn btn-default" (click)="copyDispatcherRules(fallback)">
            <span class="fa fa-paste"></span> Copy
          </button>
        </div>
        <pre class="hljs"><code [highlightAuto]="fallback"></code></pre>
      </div>

      <div id="proxy-fallback-help" *ngIf="newOperation?.dispatcher === 'PROXY_FALLBACK'">
        <br/>
        <h4>Proxy-Fallback Dispatcher</h4>
        <p>
          Proxy-Fallback dispatcher allows you to forward the incoming request to a <code>proxyUrl</code> in case it do not match
          any existing dispatch criteria.
        </p>
        <p>
          Consider the following case where you have a single <code>GET /user/:name</code> operation. You've defined mocks responses called
          <code>Andrew</code>, <code>Anna</code> and <code>John Doe</code> that are matching with corresponding <code>:name</code> resource path.
          What if name does not have one of these values?
        </p>
        <p>
          By default Microcks will return a <code>404</code> error. But if you've defined a <code>PROXY</code> dispatcher, Microcks will forward
          the original request to the external URL, the base URL of which was defined in <code>proxyUrl</code>:
        </p>
        <div style="position: absolute; right: 20px">
          <button class="btn btn-default" (click)="copyDispatcherRules(proxyFallback)">
            <span class="fa fa-paste"></span> Copy
          </button>
        </div>
        <pre class="hljs"><code [highlightAuto]="proxyFallback"></code></pre>
      </div>

      <div id="json-body-help" *ngIf="newOperation?.dispatcher === 'JSON_BODY'">
        <br/>
        <h4>JSON Body Dispatcher</h4>
        <p>
          JSON Body dispatcher allows you to introspect the content of incoming JSON payload for matching values that you'll map to response.
          It is paricully well suited for dealing with <code>POST</code> requests where you'll want different responses depending on request content.
        </p>
        <p>
          Consider the following JSON payload representing a request body for creating new Beer entity:
        </p>
        <pre class="hljs"><code [highlightAuto]="examplePayload"></code></pre>

        <p>
          Using the <code>JSON_BODY</code> dispatcher, you can select target response depending of the value of a payload element.
          Below we are checking for <code>country</code> with the <code>equals</code> operator. Note that you should always have a <code>default</code> case.
        </p>
        <div style="position: absolute; right: 20px">
          <button class="btn btn-default" (click)="copyDispatcherRules(equalsOperator)">
            <span class="fa fa-paste"></span> Copy
          </button>
        </div>
        <pre class="hljs"><code [highlightAuto]="equalsOperator"></code></pre>

        <p>
          You can also dispatch depending on a payload number value using the <code>range</code> operator. Note the orientation
          of brackets to include or exclude edge values. <code>default</code> is still required.
        </p>
        <div style="position: absolute; right: 20px">
          <button class="btn btn-default" (click)="copyDispatcherRules(rangeOperator)">
            <span class="fa fa-paste"></span> Copy
          </button>
        </div>
        <pre class="hljs"><code [highlightAuto]="rangeOperator"></code></pre>

        <p>
          The <code>size</code> operator allows you to define dispatching rules depending on the size of an array. Here we only accept
          beers that have at least 2 references and at most 100.
        </p>
        <div style="position: absolute; right: 20px">
          <button class="btn btn-default" (click)="copyDispatcherRules(sizeOperator)">
            <span class="fa fa-paste"></span> Copy
          </button>
        </div>
        <pre class="hljs"><code [highlightAuto]="sizeOperator"></code></pre>

        <p>
          For much more complex rules, you may use the <code>regexp</code> operator. There's no guarantee that cases will in the given
          order so regular expressions should be exclusives. Otherwise, it falls within the <code>default</code> case.
        </p>
        <div style="position: absolute; right: 20px">
          <button class="btn btn-default" (click)="copyDispatcherRules(regexpOperator)">
            <span class="fa fa-paste"></span> Copy
          </button>
        </div>
        <pre class="hljs"><code [highlightAuto]="regexpOperator"></code></pre>

        <p>
          Finally, you may want to dispatch according the presence of an element within JSON payload. For that, you'll use the <code>presence</code>
          operator that implies defining one <code>found</code> OR one <code>missing</code> case. Alternative falls into <code>default</code> case.
        </p>
        <div style="position: absolute; right: 20px">
          <button class="btn btn-default" (click)="copyDispatcherRules(presenceOperator)">
            <span class="fa fa-paste"></span> Copy
          </button>
        </div>
        <pre class="hljs"><code [highlightAuto]="presenceOperator"></code></pre>
      </div>
    </div>
  </div>
</div>
